﻿using StockTradTest;
using StockTradTest.Data;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using StockTradTest.strategy;

namespace TestGraphic
{
    public partial class Form1 : Form
    {

        
        double maxPrice = 0;
        double minPrice = double.MaxValue;
        //股票基本信息
        StockInfo baseInfo = null;
        //股票历史数据
        List<Stock>  stockData = null;
        List<Indicator> indicators = null;
        //买卖点
        List<int> buyOrSell;

        const double stockPersent = 0.45f;
        const double bollPersent = 0.23f;
        const double volumePersent = 0.2f;


        Graphics graphics;
        readonly Pen pen;
        readonly Brush brush;
        //鼠标按下时候的位置记录
        Point mouseDownPoint = Point.Empty;
        bool LMouseDown = false;
        //显示的开始位置
        int showStartCount = 0;
        //显示总数
        int showCount = 0;
        //记录的
        int oldShowStartCount = 0;
        //最大计数
        int maxCount = 0;
        //绘图用缓存
        Bitmap bmp;
        //窗口处于处理阶段
        public static bool inFocus = true;

        //线的x坐标
        int lineX = -1;
        readonly Form2 textForm;
        public Form1()
        {
            pen = new Pen(Color.Black, 1);
            brush = new SolidBrush(Color.DarkGray);
            InitializeComponent();
            bmp = new Bitmap(Width, Height);
            graphics = Graphics.FromImage(bmp);
            textBox_code.Text = "601166";
            textBox_variable.Text = "20";
            textForm = new Form2();
            textForm.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseMove);
            textForm.m_Label.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseMove);
            //textForm.label_Text.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Form5_MouseMove);
            textForm.Visible = false;

            GraphicsClear();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            this.CreateGraphics().DrawImage(bmp, 0, 0);

        }
        private void DrawStock(int startCount = 0)
        {

            maxPrice = 0;
            minPrice = double.MaxValue;

            double heightLength = Height * stockPersent - 5;
            if (stockData == null) return;
            maxCount = stockData.Count;
            showCount = (int)Math.Floor((Width - 25) / 5f);
            //开始点+显示点>最大点数
            if (startCount + showCount >= maxCount)
            {
                startCount = maxCount - showCount;
                showStartCount = startCount;
            }
            for (int i = startCount; i < startCount + showCount; i++)
            {
                if (maxPrice < stockData[i].HighPrice) maxPrice = stockData[i].HighPrice;
                if (minPrice > stockData[i].LowPrice) minPrice = stockData[i].LowPrice;
            }
            List<Point> points = new List<Point>();
            double length = maxPrice - minPrice;

            for (int i = 0; i < showCount; i++)
            {
                //if (i + startCount == maxCount) break;
                Point point1 = new Point(i * 5 + 4, 5 + (int)(heightLength - (stockData[i + startCount].HighPrice - minPrice) / length * heightLength));
                Point point2 = new Point(i * 5 + 4, 5 + (int)(heightLength - (stockData[i + startCount].LowPrice - minPrice) / length * heightLength));
                Point point3 = new Point(i * 5 + 4, 5 + (int)(heightLength - (stockData[i + startCount].OpenPrice - minPrice) / length * heightLength));
                Point point4 = new Point(i * 5 + 4, 5 + (int)(heightLength - (stockData[i + startCount].ClosePrice - minPrice) / length * heightLength));
                if (stockData[i + startCount].OpenPrice < stockData[i + startCount].ClosePrice)
                {
                    graphics.DrawLine(new Pen(Color.Red, 1), point1, point2);
                    graphics.DrawLine(new Pen(Color.Red, 3), point3, point4);
                }
                else
                {
                    graphics.DrawLine(new Pen(Color.Green, 1), point1, point2);
                    graphics.DrawLine(new Pen(Color.Green, 3), point3, point4);
                }
                if (buyOrSell != null)
                {
                    if(buyOrSell[i + startCount] == 1)
                    {
                        DrawArrow(point2, true);
                    }
                    else if (buyOrSell[i + startCount] == -1)
                    {
                        DrawArrow(point1, false);
                    }
                }

            }
            if (points.Count == 0) return;
            int count = 0;
            for (int i = 0; i < showCount; i++)
            {
                graphics.DrawLine(pen, points[count++], points[count++]);
            }

        }
        /// <summary>
        /// 在主图上绘制Ma移动平均线
        /// </summary>
        /// <param name="code">股票代码</param>
        /// <param name="n">ma天数</param>
        /// <param name="startCount">开始数据</param>
        private void DrawMa(int n, Color color)
        {
            double heightLength = Height * stockPersent - 5;
            if (indicators == null) return;
            List<Point> points = new List<Point>();
            double length = maxPrice - minPrice;
            double tempMa;
            for (int i = 0; i < showCount; i++)
            {
                tempMa = n switch
                {
                    5 => indicators[i + showStartCount].Ma5,
                    10 => indicators[i + showStartCount].Ma10,
                    20 => indicators[i + showStartCount].Ma20,
                    30 => indicators[i + showStartCount].Ma60,
                    60 => indicators[i + showStartCount].Ma60,
                    120 => indicators[i + showStartCount].Ma120,
                    250 => indicators[i + showStartCount].Ma250,
                    _ => 0
                };

                points.Add( new Point(i * 5 + 4, 5 + (int)(heightLength - (tempMa - minPrice) / length * heightLength)));
            }
            if(points.Count >0)graphics.DrawLines(new Pen(color, 1), points.ToArray());

        }
        /// <summary>
        /// 绘制换手量和成交资金量
        /// </summary>
        /// <param name="startCount"></param>
        private void DrawVolume()
        {
            double heightLength = Height * volumePersent - 5;
            double title = Height * (stockPersent + volumePersent) + 4;
            if (stockData == null || stockData.Count == 0) return;
            double maxHand = 0;
            double maxAmount = 0;
            for (int i = showStartCount; i < showCount + showStartCount; i++)
            {
                if (maxHand < stockData[i].TotalHand) maxHand = stockData[i].TotalHand;
                if (maxAmount < stockData[i].TotalAmount) maxAmount = stockData[i].TotalAmount;
            }
            for (int i = 0; i < showCount; i++)
            {
                Point point1 = new Point(i * 5 + 3, (int)title);
                Point point2 = new Point(i * 5 + 3, (int)(title - stockData[i + showStartCount].TotalHand / maxHand * heightLength));
                Point point3 = new Point(i * 5 + 5, (int)title);
                Point point4 = new Point(i * 5 + 5, (int)(title - stockData[i + showStartCount].TotalAmount / maxAmount * heightLength));
                graphics.DrawLine(new Pen(Color.LightGreen, 2), point3, point4);
                graphics.DrawLine(new Pen(Color.DarkRed, 2), point1, point2);
            }

        }
        private void DrawBoll()
        {
            double heightLength = Height * bollPersent - 5;
            double title = Height * (stockPersent + volumePersent + bollPersent) + 5;
            if (stockData == null || stockData.Count == 0) return;
            double maxPrice = 0;
            double minPrice = double.MaxValue;
            for (int i = showStartCount; i < showCount + showStartCount; i++)
            {
                if (maxPrice < indicators[i].BollUp) maxPrice = indicators[i].BollUp;
                if (minPrice > indicators[i].BollDown) minPrice = indicators[i].BollDown;
                if (maxPrice < stockData[i].HighPrice) maxPrice = stockData[i].HighPrice;
                if (minPrice > stockData[i].LowPrice) minPrice = stockData[i].LowPrice;
            }
            List<Point> pointsUp = new List<Point>();
            List<Point> pointsMd = new List<Point>();
            List<Point> pointsDown = new List<Point>();
            double length = maxPrice - minPrice;
            for (int i = 0; i < showCount; i++)
            {
                pointsUp.Add(new Point(i * 5 + 4, (int)(title - (indicators[i + showStartCount].BollUp - minPrice) / length * heightLength)));
                pointsMd.Add(new Point(i * 5 + 4, (int)(title - (indicators[i + showStartCount].BollMd - minPrice) / length * heightLength)));
                pointsDown.Add(new Point(i * 5 + 4, (int)(title - (indicators[i + showStartCount].BollDown - minPrice) / length * heightLength)));
            }
            if (pointsUp.Count > 0)
            {
                graphics.DrawLines(new Pen(Color.White, 1), pointsUp.ToArray());
                graphics.DrawLines(new Pen(Color.Yellow, 1), pointsMd.ToArray());
                graphics.DrawLines(new Pen(Color.Purple, 1), pointsDown.ToArray());
            }
            //Draw Stock on Indicator
            
            if (stockData == null) return;
            List<Point> points = new List<Point>();

            for (int i = 0; i < showCount; i++)
            {
                Point point1 = new Point(i * 5 + 4,  (int)(title - (stockData[i + showStartCount].HighPrice - minPrice) / length * heightLength));
                Point point2 = new Point(i * 5 + 4, (int)(title - (stockData[i + showStartCount].LowPrice - minPrice) / length * heightLength));
                Point point3 = new Point(i * 5 + 4,  (int)(title - (stockData[i + showStartCount].OpenPrice - minPrice) / length * heightLength));
                Point point4 = new Point(i * 5 + 4, (int)(title - (stockData[i + showStartCount].ClosePrice - minPrice) / length * heightLength));
                if (stockData[i].OpenPrice < stockData[i].ClosePrice)
                {
                    graphics.DrawLine(new Pen(Color.Red, 1), point1, point2);
                    graphics.DrawLine(new Pen(Color.Red, 3), point3, point4);
                }
                else
                {
                    graphics.DrawLine(new Pen(Color.Green, 1), point1, point2);
                    graphics.DrawLine(new Pen(Color.Green, 3), point3, point4);
                }

            }
            if (points.Count == 0) return;
            int count = 0;
            for (int i = 0; i < showCount; i++)
            {
                graphics.DrawLine(pen, points[count++], points[count++]);
            }

        }
        private void DrawAll(int startCount)
        {
            DrawStock(startCount);
            DrawMa(20, Color.LightGreen);
            DrawMa(60, Color.Red);
            DrawVolume();
            DrawBoll();
        }
        private void DrawArrow(Point point,bool isUp)
        {
            Bitmap arrow = Resource1.arrow;
            if(isUp)
            {
                arrow.RotateFlip(RotateFlipType.Rotate180FlipNone);
                point.Y += 2;
            }
            else
            {
                point.Y -= (int)(arrow.Height * 0.2) + 2;
            }
            point.X -= (int)(arrow.Width * 0.1);
            graphics.DrawImage(arrow,new Rectangle(point.X, point.Y, (int)(arrow.Width * 0.2), (int)(arrow.Height * 0.2)),
                new Rectangle(0, 0, arrow.Width, arrow.Height),
                GraphicsUnit.Pixel);
        }
        private void Clear()
        {
            if(Base.CurrentCode != textBox_code.Text)
            {
                Base.CurrentCode = "";
                stockData = null;
                indicators = null;
                maxCount = 0;
            }
            GraphicsClear();
        }

        private void GraphicsClear()
        {
            graphics.Clear(Color.WhiteSmoke);
            graphics.FillRectangle(brush, new RectangleF(2, 2, Width - 20, (int)(Height * stockPersent)));
            graphics.DrawRectangle(pen, new Rectangle(1, 1, Width - (int)pen.Width - 18, (int)(Height * stockPersent)));
            graphics.FillRectangle(brush, new RectangleF(2, (int)(Height * stockPersent + 5), Width - 20, (int)(Height * volumePersent)));
            graphics.DrawRectangle(pen, new Rectangle(1, (int)(Height * stockPersent + 5), Width - (int)pen.Width - 18, (int)(Height * volumePersent)));
            graphics.FillRectangle(brush, new RectangleF(2, (int)(Height * (stockPersent + volumePersent) + 10), Width - 20, (int)(Height * bollPersent)));
            graphics.DrawRectangle(pen, new Rectangle(1, (int)(Height * (stockPersent + volumePersent) + 10), Width - (int)pen.Width - 18, (int)(Height * bollPersent)));
        }
        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {

            textForm.Visible = false;
            if (e.Button == MouseButtons.Left)
            {
                Cursor = Cursors.Hand;
                
                if(LMouseDown == false)
                {
                    mouseDownPoint = new Point(-e.X, -e.Y);
                    LMouseDown = true;
                    oldShowStartCount = showStartCount;
                    return;
                }
            }

        }

        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            LMouseDown = false;
            Cursor = Cursors.Default;
            oldShowStartCount = showStartCount;
        }

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (!inFocus) return;
            if (LMouseDown)
            {
                showStartCount = oldShowStartCount + (-e.X - mouseDownPoint.X)/5;
                if (showStartCount < 0) showStartCount = 0;
                if (showStartCount != oldShowStartCount)
                {
                    
                    label_Msg.Text = showStartCount.ToString();
                    Clear();

                    DrawAll(showStartCount);
                    //this.CreateGraphics().DrawImage(bmp, 0, 0);
                }
            }
            else
            {
                if (baseInfo == null || stockData == null || indicators == null)
                {
                    return;
                }
                Point p = this.PointToClient(Cursor.Position);
                if (p.X <= Width * 0.8)
                {
                    if(p.Y < Height * 0.5)
                    {
                        textForm.Location = this.PointToScreen(new Point(p.X + 10, p.Y));
                    }
                    else
                    {
                        textForm.Location = this.PointToScreen(new Point(p.X + 10, p.Y - textForm.Height - 10));
                    }
                }
                else
                {
                    if (p.Y < Height * 0.5)
                    {
                        textForm.Location = this.PointToScreen(new Point(p.X - textForm.Width - 10, p.Y));
                    }
                    else
                    {
                        textForm.Location = this.PointToScreen(new Point(p.X - textForm.Width - 10, p.Y - textForm.Height - 10));
                    }
                }
                if (textForm.Visible == false) textForm.Visible = true;
                if (this.ClientSize.Width > p.X & 0 < p.X & this.ClientSize.Height - 30 > p.Y & 0 < p.Y)
                {
                    int x = (int)((MousePosition.X - this.Location.X) / 5) * 5 - 6;
                    if (lineX != x)
                    {
                        lineX = x;
                        GraphicsClear();

                        DrawAll(showStartCount);

                        int dateCount = showStartCount + (x - 4) / 5;
                        if (dateCount > 0 & dateCount < maxCount)
                        {
                            Stock dayData = stockData[showStartCount + (x - 4) / 5];
                            Indicator dayIndicator = indicators[showStartCount + (x - 4) / 5];
                            string text = string.Format("代码:{0}\n" +
                                "名称:{1}\n" +
                                "日期:{2}\n" +
                                "开盘:{3}\n" +
                                "收盘:{4}\n" +
                                "最高:{5}\n" +
                                "最低:{6}\n" +
                                "手数:{7}\n" +
                                "换手率:{8}%\n" +
                                "成交额:{9}\n" +
                                "20日均线:{10}\n" +
                                "布林上轨:{11}\n" +
                                "布林中轨:{12}\n" +
                                "布林下轨:{13}\n",
                                Base.CurrentCode,
                                baseInfo.Name.ToString(),
                                dayData.Date.ToString(),
                                dayData.OpenPrice,
                                dayData.ClosePrice,
                                dayData.HighPrice,
                                dayData.LowPrice,
                                dayData.TotalHand,
                                dayData.HandRate,
                                dayData.TotalAmount,
                                dayIndicator.Ma20.ToString("F2"),
                                dayIndicator.BollUp.ToString("F2"),
                                dayIndicator.BollMd.ToString("F2"),
                                dayIndicator.BollDown.ToString("F2"));
                            textForm.m_Text = text;
                        }


                        graphics.DrawLine(new Pen(Color.Black, 1), new Point(x, 1), new Point(x, (int)(Height * 0.89)));
                        this.CreateGraphics().DrawImage(bmp, 0, 0);
                    }

                }
                else
                {
                    textForm.Visible = false;
                }
            }
            

        }


        private async Task<bool> RunOnceAsync(string code,int n)
        {
            if (baseInfo == null || Base.CurrentCode != code)
                baseInfo = Base.StockInfoDatabase.GetStockInfoAsync(code).Result;
            if (baseInfo == null)
                return false;
            Base.CurrentCode = code;
            await foreach (string str in GetStockHistory.UpdateDayAsync(code))
            {
                label_Msg.Text = str;
            }
            label_Msg.Text = "";
            
            stockData = Base.StockDatabase.GetStockAsync().Result;

            indicators = Base.IndicatorDatabase.GetIndicatorAsync().Result;
            CalcIndicator.CalcBoll(n, stockData, ref indicators);
            return true;
        }
        private async void Button_find_ClickAsync(object sender, EventArgs e)
        {
            if(textBox_code.Text.Length!=6)
            {
                textBox_code.BackColor = Color.Red;
                return;
            }
            Clear();
            if(!int.TryParse(textBox_variable.Text,out int n))
            {
                return;
            }
            if(await RunOnceAsync(textBox_code.Text,n))
            {
                //MyStrategy.TradeAberrationPlusTest(textBox_code.Text, n, out buyOrSell, true);
                MyStrategy.TradeMiddleTest(textBox_code.Text, n, out buyOrSell, true);
                showStartCount = oldShowStartCount = stockData.Count;
                DrawAll(showStartCount);
            }
            else
            {
                label_Msg.Text = "输入错误";
            }

        }
        private void Button_goto_Click(object sender, EventArgs e)
        {

            if (textBox_Date.Text.Length != 8)
            {
                textBox_Date.BackColor = Color.Red;
                textBox_Date.Text = "长度错误";
                return;
            }
            else
            {
                textBox_Date.BackColor = Color.White;
            }
            int.TryParse(textBox_Date.Text, out int date);
            int count = 0;
            foreach (var dayData in stockData)
            {
                if (dayData.Date >= date || count >= stockData.Count - 20)
                {
                    Clear();
                    showStartCount = oldShowStartCount = count;
                    DrawAll(showStartCount);

                    return;
                }
                count++;
            }

            //DateTime date = new DateTime(), textBox1.Text.Take(4), textBox1.Text.Take(4));
        }
        private void Button_Clear_Click(object sender, EventArgs e)
        {
            textBox_code.Text = "";
            Clear();
        }
        private void Button_Strategy_Click(object sender, EventArgs e)
        {
            inFocus = false;
            textForm.Visible = false;
            Form3 form3 = new Form3();
            form3.Show();
        }

        private void button_log_Click(object sender, EventArgs e)
        {
            TextRecord.Record(TestTradBase.record, true);
            TextRecord.OpenRecord();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            textForm.Close();
        }
        private void Form1_Resize(object sender, EventArgs e)
        {
            bmp = new Bitmap(this.Size.Width, this.Size.Height);
            graphics = Graphics.FromImage(bmp);
            GraphicsClear();
        }
    }
}
